package com.wanjia.estate.service.httpservice;

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.unionpay.acp.sdk.Acp6Service;
import com.unionpay.acp.sdk.CertUtil;
import com.unionpay.acp.sdk.SDKConfig;
import com.unionpay.acp.sdk.SDKUtil;
import com.wanjia.estate.pojo.bank.CommonHeader;
import com.wanjia.estate.pojo.bank.Pay;
import com.wanjia.estate.properties.BankPayProperties;
import com.wanjia.estate.utils.ThreadUtil;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.*;

@Service
@Slf4j
public class BankPayService extends AbstractHttpService {

    public static final String ENCODING = "UTF-8";

    @Setter(onMethod_ = @Autowired)
    private BankPayProperties properties;

    public Pay.Response pay(Pay.Header header, Pay.Request request) {
        String url = SDKConfig.getConfig().getTransUrl();
        Date now = ThreadUtil.getNow();
        String uuid = UUID.randomUUID().toString();

        JSONObject requestJson = (JSONObject) JSON.toJSON(request);
        JSONObject headerJson = (JSONObject) JSON.toJSON(header);

        request.setOrderId(uuid);
        SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss");
        request.setTxnTime(formatter.format(now));

        SDKConfig config = SDKConfig.getConfig();
        String certPath = config.getSignCertPath();
        String certPwd = config.getSignCertPwd();

        header.setReqId(uuid);
        header.setSignMethod(CommonHeader.RSA2);
        header.setSignId(CertUtil.getCertIdByKeyStoreMap(certPath, certPwd));
        header.setSign(SDKUtil.signRsa2(requestJson, certPath, certPwd, BankPayService.ENCODING));

        log.debug("request url: {}", url);
        log.debug("request body: {}", JSONUtil.toJsonStr(request));
        log.debug("request header: {}", JSONUtil.toJsonStr(header));

        RequestEntity.BodyBuilder builder = RequestEntity.post(url);
        if (header != null) {
            headerJson.forEach((k, v) -> builder.header(k, Objects.toString(v)));
        }
        RequestEntity<String> requestEntity = builder
                .contentType(MediaType.APPLICATION_JSON)
                .body(requestJson.toJSONString());
        ResponseEntity<String> entity = template.exchange(requestEntity, String.class);
        Pay.Response response = parseObjResponseEntity2(entity, Pay.Response.class);
        log.debug("response body: {}", JSONUtil.toJsonStr(response));

        return response;
    }

    public Pay.Response pay2(Pay.Header header, Pay.Request request) {
        String url = SDKConfig.getConfig().getTransUrl();
        Date now = ThreadUtil.getNow();
        String uuid = UUID.randomUUID().toString();

        JSONObject requestJson = (JSONObject) JSON.toJSON(request);
        JSONObject headerJson = (JSONObject) JSON.toJSON(header);

        request.setOrderId(uuid);
        SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss");
        request.setTxnTime(formatter.format(now));

        header.setReqId(uuid);
        header.setSignMethod(CommonHeader.RSA2);

        log.debug("request url: {}", url);
        log.debug("request body: {}", JSONUtil.toJsonStr(request));
        log.debug("request header: {}", JSONUtil.toJsonStr(header));

        Map<String, String> reqData = new TreeMap<String, String>();
        headerJson.forEach((k, v) -> reqData.put(k, Objects.toString(v)));
        reqData.put("bizContent", requestJson.toString());
        Map<String, String> reqMap = Acp6Service.sign(reqData, ENCODING);
        Map<String, String> rspMap = Acp6Service.post(reqMap, url, ENCODING);

        JSONObject responseJson = (JSONObject) JSON.toJSON(rspMap);
        log.debug("response body: {}", responseJson);

        return JSON.toJavaObject(responseJson, Pay.Response.class);
    }
}
